import { Popup, SafeArea } from '@nutui/nutui-react-taro';
import { View, Text, RootPortal } from '@tarojs/components';
import classnames from 'classnames';
import {
  forwardRef,
  Fragment,
  useImperativeHandle,
  useRef,
  useState,
  useEffect,
} from 'react';
import Taro, { useDidShow } from '@tarojs/taro';

import type { ReactNode } from 'react';

import './index.scss';
import { useActionSheetStore } from '@/models';

interface Option {
  key: string;
  name: string;
  description?: string;
  danger?: boolean;
  disabled?: boolean;
  show?: boolean;
}

export interface ActionType {
  setOpen: (open: boolean) => void;
}

interface ActionSheetProps {
  options: Option[];
  children?: ReactNode;
  className?: string;
  cancelText?: string;
  onSelect?: (item: Option, index: number) => void;
  onCancel?: () => void;
  onClose?: () => void;
  portal?: HTMLElement;
  zIndex?: number;
  destroyOnClose?: boolean;
  actionSheetId?: string;
}

const PREFIX_CLS = 'm-action-sheet';

const ActionSheet = forwardRef<ActionType, ActionSheetProps>(
  (
    {
      className,
      children,
      options,
      cancelText = '取消',
      onSelect,
      onCancel,
      onClose,
      portal,
      zIndex = 1000,
      destroyOnClose = true,
      actionSheetId,
      ...rest
    },
    ref,
  ) => {
    useImperativeHandle(ref, () => {
      return {
        setOpen: (open) => {
          if (open) {
            openSelf();
          } else {
            closeSelf();
          }
        },
      };
    });

    const randomUid = `${PREFIX_CLS}-${Date.now().toString(36)}-${Math.random()
      .toString(36)
      .slice(2, 8)}`;
    const uidRef = useRef<string>(
      actionSheetId ? `${PREFIX_CLS}-${String(actionSheetId)}` : randomUid,
    );

    useEffect(() => {
      if (actionSheetId) {
        const next = `${PREFIX_CLS}-${String(actionSheetId)}`;
        if (uidRef.current !== next) {
          uidRef.current = next;
        }
      }
    }, [actionSheetId]);

    const { isTabbarPage, visibleUid, open, close } = useActionSheetStore(
      (state) => state,
    );

    const isActive = visibleUid === uidRef.current;

    const [popupKey, setPopupKey] = useState<number>(0);
    useDidShow(() => {
      setPopupKey((k) => k + 1);
    });

    useEffect(() => {
      // when visibleUid changes, no additional state is needed; Popup uses isActive
    }, [visibleUid]);

    // In H5, explicitly mount to document.body to avoid scroll containers;
    // In mini-programs, omit the portal prop entirely.
    const isWeb = Taro.getEnv && Taro.getEnv() === Taro.ENV_TYPE.WEB;
    const rootDom = isWeb
      ? typeof document !== 'undefined'
        ? portal || (document.body as HTMLElement)
        : undefined
      : undefined;

    // For H5, compute safe-area spacer
    let spacerHeight = 0;
    if (isWeb) {
      const sys = Taro.getSystemInfoSync();
      spacerHeight = Math.max(
        0,
        sys.screenHeight - (sys.safeArea?.bottom ?? sys.screenHeight),
      );
    }

    const openSelf = () => {
      open(uidRef.current);
    };
    const closeSelf = () => {
      if (visibleUid === uidRef.current) {
        close();
      }
    };

    const handleOptionClick = (option: Option, index: number) => {
      if (option.disabled) return;
      closeSelf();
      onSelect?.(option, index);
    };

    const handleCancelClick = () => {
      closeSelf();
      onCancel?.();
    };

    const handleOverlayClick = () => {
      closeSelf();
      onClose?.();
    };

    const visibleOptions = options.filter(({ show = true }) => show);

    // build props for Popup with conditional portal (H5 only)
    const popupExtraProps = isWeb && rootDom ? { portal: rootDom } : {};

    const popupNode = (
      <Popup
        key={popupKey}
        visible={isActive}
        position="bottom"
        round
        onClose={handleOverlayClick}
        className={classnames(PREFIX_CLS, className)}
        onOverlayClick={(e) => {
          e.stopPropagation();
          handleOverlayClick();
        }}
        zIndex={zIndex}
        destroyOnClose={destroyOnClose}
        {...popupExtraProps}
        {...rest}
      >
        <View className={`${PREFIX_CLS}-content`}>
          <View className={`${PREFIX_CLS}-options`}>
            {visibleOptions.map((option, index) => (
              <View
                key={option.key}
                className={classnames(`${PREFIX_CLS}-option`, {
                  [`${PREFIX_CLS}-option--danger`]: option.danger,
                  [`${PREFIX_CLS}-option--disabled`]: option.disabled,
                })}
                onClick={(e) => {
                  e.stopPropagation();
                  handleOptionClick(option, index);
                }}
              >
                <Text className={`${PREFIX_CLS}-option-text`}>
                  {option.name}
                </Text>
                {option.description && (
                  <Text className={`${PREFIX_CLS}-option-desc`}>
                    {option.description}
                  </Text>
                )}
              </View>
            ))}
          </View>

          <View
            className={`${PREFIX_CLS}-cancel`}
            onClick={(e) => {
              e.stopPropagation();
              handleCancelClick();
            }}
          >
            <Text className={`${PREFIX_CLS}-cancel-text`}>{cancelText}</Text>
          </View>

          {isWeb && spacerHeight > 0 ? (
            <View style={{ height: `${spacerHeight}px` }} />
          ) : null}
          {!isWeb && <SafeArea position="bottom" />}
          {!isWeb && isTabbarPage ? <View style={{ height: '68px' }} /> : null}
        </View>
      </Popup>
    );

    return (
      <Fragment>
        <View
          className={`${PREFIX_CLS}-view`}
          onClick={(e) => {
            e.stopPropagation();
            openSelf();
          }}
        >
          {children}
        </View>

        {isWeb ? popupNode : <RootPortal>{popupNode}</RootPortal>}
      </Fragment>
    );
  },
);

export default ActionSheet;
